package com.xu.tools.minio;

import io.minio.*;
import io.minio.http.Method;
import io.minio.messages.Bucket;
import io.minio.messages.Item;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author xuguan
 * @date 2023/2/16
 * @desc minio操作接口实现类
 */
@Slf4j
@Service
public class MinoServiceImpl implements MinioService {
    @Autowired
    MinioClient minioClient;

    public List<Bucket> listBuckets() {
        log.info("开始查询所有桶列表");
        try {
            List<Bucket> buckets = minioClient.listBuckets();
            return buckets;
        } catch (Exception e) {
            throw new RuntimeException("查询所有桶列表失败");
        }
    }

    public boolean bucketExists(String bucket) {
        log.info("开始检查桶是否存在, bucket={}", bucket);
        try {
            BucketExistsArgs bucketExistsArgs = BucketExistsArgs.builder()
                    .bucket(bucket)
                    .build();
            boolean bucketExists = minioClient.bucketExists(bucketExistsArgs);

            return bucketExists;
        } catch (Exception e) {
            throw new RuntimeException("检查桶是否存在失败");
        }
    }

    public void makeBucket(String bucket) {
        log.info("开始创建桶, bucket={}", bucket);
        try {
            MakeBucketArgs makeBucketArgs = MakeBucketArgs.builder()
                    .bucket(bucket)
                    .build();
            minioClient.makeBucket(makeBucketArgs);
        } catch (Exception e) {
            throw new RuntimeException("创建桶失败");
        }
    }

    public void removeBucket(String bucket) {
        log.info("开始删除桶, bucket={}", bucket);
        try {
            RemoveBucketArgs removeBucketArgs = RemoveBucketArgs.builder()
                    .bucket(bucket)
                    .build();
            minioClient.removeBucket(removeBucketArgs);
        } catch (Exception e) {
            throw new RuntimeException("删除桶失败");
        }
    }

    @Override
    public Iterable<Result<Item>> listObject(String bucket) {
        log.info("开始获取桶中所有文件, bucket={}", bucket);

        try {
            // 查看是否在文件系统存在
            ListObjectsArgs listObjectsArgs = ListObjectsArgs.builder()
                    .bucket(bucket)
                    .build();
            Iterable<Result<Item>> iterable = minioClient.listObjects(listObjectsArgs);

            return iterable;
        } catch (Exception e) {
            throw new RuntimeException("获取桶中所有文件失败");
        }
    }

    @Override
    public InputStream getObject(String bucket, String objectName) {
        log.info("开始获取文件, bucket={}, objectName={}", bucket, objectName);

        try {
            // 查看是否在文件系统存在
            GetObjectArgs getObjectArgs = GetObjectArgs.builder()
                    .bucket(bucket)
                    .object(objectName)
                    .build();
            InputStream inputStream = minioClient.getObject(getObjectArgs);

            return inputStream;
        } catch (Exception e) {
            throw new RuntimeException("获取文件失败");
        }
    }

    @Override
    public boolean objectExists(String bucket, String objectName) {
        log.info("开始检查文件是否存在, bucket={}, objectName={}", bucket, objectName);
        InputStream is = getObject(bucket, objectName);
        return is != null;
    }

    @Override
    public String getPreSignedObjectUrl(String bucket, String objectName) {
        log.info("开始生成预览url地址, bucket={}, objectName={}", bucket, objectName);

        GetPresignedObjectUrlArgs getPresignedObjectUrlArgs = GetPresignedObjectUrlArgs.builder()
                .bucket(bucket)
                .object(objectName)
                .method(Method.GET)
                .expiry(1, TimeUnit.DAYS)
                .build();
        try {
            String preSignedObjectUrl = minioClient.getPresignedObjectUrl(getPresignedObjectUrlArgs);

            return preSignedObjectUrl;
        } catch (Exception e) {
            throw new RuntimeException("生成预览url地址失败");
        }
    }

    public void uploadObject(String fileName, String contentType, String bucket, String objectName) {
        log.info("开始上传文件, fileName={}, bucket={}, objectName={}", fileName, bucket, objectName);

        try {
            UploadObjectArgs uploadObjectArgs = UploadObjectArgs.builder()
                    .bucket(bucket)
                    .object(objectName)
                    .filename(fileName)
                    .contentType(contentType)
                    .build();
            minioClient.uploadObject(uploadObjectArgs);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void uploadObject(byte[] uploadFileBytes, String contentType, String bucket, String objectName) {
        log.info("开始上传文件, bucket={}, objectName={}", bucket, objectName);

        try {
            ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(uploadFileBytes);
            PutObjectArgs putObjectArgs = PutObjectArgs.builder()
                    .bucket(bucket)
                    .object(objectName)
                    // InputStream stream, long objectSize 对象大小, long partSize 分片大小(-1表示5M,最大不要超过5T，最多10000)
                    .stream(byteArrayInputStream, byteArrayInputStream.available(), -1)
                    .contentType(contentType)
                    .build();
            // 上传到minio
            minioClient.putObject(putObjectArgs);
        } catch (Exception e) {
            throw new RuntimeException("上传文件失败");
        }
    }

    @Override
    public void downloadObject(String bucket, String objectName, String downloadFileName) {
        log.info("开始下载文件, bucket={}, objectName={}", bucket, objectName);

        DownloadObjectArgs downloadObjectArgs = DownloadObjectArgs.builder()
                .bucket(bucket)
                .object(objectName)
                .filename(downloadFileName) // 下载完成后的文件名称
                .build();
        try {
            minioClient.downloadObject(downloadObjectArgs);
        } catch (Exception e) {
            throw new RuntimeException("文件下载失败");
        }
    }


    @Override
    public void removeObject(String bucket, String objectName) {
        log.info("开始删除文件, bucket={}, objectName={}", bucket, objectName);

        RemoveObjectArgs removeObjectArgs = RemoveObjectArgs.builder()
                .bucket(bucket)
                .object(objectName)
                .build();
        try {
            minioClient.removeObject(removeObjectArgs);
        } catch (Exception e) {
            throw new RuntimeException("删除文件失败");
        }
    }
}
